
#include "fieldactor.h"
#include "physics.h"
#include "..\common\def.h"
#include "..\common\util.h"
#include "..\engine\error.h"
#include "..\engine\engine.h"
#include "..\engine\time.h"

#include "Physics\Dynamics\Entity\hkpRigidBodyCinfo.h"
#include "Physics\Dynamics\World\hkpPhysicsSystem.h"
#include "Physics\Utilities\Serialize\hkpPhysicsData.h"
#include "Common\SceneData\Scene\hkxScene.h"
#include "Common\Serialize\Util\hkLoader.h"
#include "Common\Serialize\Util\hkRootLevelContainer.h"
#include "Physics\Collide\Shape\Compound\Collection\hkpShapeCollection.h"
#include "common\base\math\vector\hkVector4.h"
#include "Common\Base\Types\hkBaseTypes.h"

#include "Common\Base\Types\Physics\hkStepInfo.h"
#include "Common\Base\Math\Matrix\hkTransform.h"
#include "Physics\Dynamics\Phantom\hkpCachingShapePhantom.h"


class FieldPenetrate : public hkpPhantomOverlapListener 
{
public:

	CObject* m_pOther;
	CObject* m_pOwner;

	FieldPenetrate(CObject* pOwner, CObject *pOther) : m_pOther(pOther) , m_pOwner(pOwner)
	{

	}

	void collidableAddedCallback(   const hkpCollidableAddedEvent& event ) 
	{

		hkpRigidBody* bodyA = static_cast<hkpRigidBody*>(event.m_collidable->getOwner());
		if(bodyA) {
			CObject* pOtherObject = (CObject*)bodyA->getUserData();
			if(pOtherObject == m_pOther) {
				
				m_pOwner->OnCollisionEvent(Vector3f(), Vector3f(), m_pOther);
			}
		}

	}

	void collidableRemovedCallback( const hkpCollidableRemovedEvent& event ) 
	{

	}

};

/**************************************
 *
 **************************************/
CFieldActor::CFieldActor(CPhysics* const pPhysics) : CActor(pPhysics)
{	
	m_pPhantom = NULL;
	m_pParent = NULL;
}

/**************************************
 *
 **************************************/
CFieldActor::~CFieldActor()
{
	Release();
}

/**************************************
 *Allocates physics resources which are
 *defined by data within the specified file
 *for use in the application
 **************************************/
HRESULT CFieldActor::Create(const string& filename, CFieldActor::ActorData actorData,CObject *pParent)
{
	return Create(filename, actorData.initalTransform, pParent);
}

/**************************************
 *Checks to see if registered colidables
 *are overlapping
 **************************************/
void CFieldActor::Simulate() {

}

void CFieldActor::SetCollisionCallback(CObject* pObject) {

	m_pPhantom->addPhantomOverlapListener(new FieldPenetrate(m_pParent, pObject));

}

/**************************************
 *Allocates physics resources which are
 *defined by data within the specified file
 *for use in the application
 **************************************/
HRESULT CFieldActor::Create(const string& filename, const Matrix4f &initalTransform, CObject *pParent)
{
	HRESULT hr;
	const string filepath = CEngine::GetInstance()->FindFilepath(filename);
	hkLoader* m_loader = NULL;
	hkRootLevelContainer* container = NULL;
	hkpRigidBodyCinfo c;
	hkpCachingShapePhantom* pPhantom = NULL;

	const hkpShape *shape = NULL;
	do {

		if(ISNULL(m_pPhysics->GetScene())) {
			EE_LOGERROR("Bad engine state.");
			hr = E_UNEXPECTED;
			break;
		}

		if(!filepath.IsValid()) {
			EE_LOGERROR("Bad filename.")
			hr = E_INVALIDARG;
			break;
		}

		m_loader = new hkLoader();
		if(ISNULL(m_loader)) {
			hr = E_OUTOFMEMORY;
			break;
		}

		container = m_loader->load(filepath.c_str());
		if(ISNULL(container)) {
			hr = E_UNEXPECTED;
			break;
		}

		hkpPhysicsData* physics = reinterpret_cast<hkpPhysicsData*>( container->findObjectByType( hkpPhysicsDataClass.getName() ));
		if(ISNULL(physics)) {
			hr = E_UNEXPECTED;
			break;
		}

		const hkArray<hkpPhysicsSystem*>& psys = physics->getPhysicsSystems();

		if(psys.getSize() == 0) {
			hr = E_UNEXPECTED;
			break;
		}

		hkpPhysicsSystem* system = psys[0];

		if(ISNULL(system) || system->getRigidBodies().isEmpty()) {
			hr = E_UNEXPECTED;
			break;
		}

		hkpRigidBody* pActor = system->getRigidBodies()[0];
		if(ISNULL(pActor)) {
			hr = E_UNEXPECTED;
			break;
		}

		pActor->getCinfo(c);
		shape = c.m_shape;
		if(ISNULL(shape)) {
			hr = E_UNEXPECTED;
			break;
		}

		hkTransform t = TohkTransform(initalTransform);
		if(!t.isOk()) {
			EE_LOGERROR("Warning: bad field transform.");
			t.setIdentity();
		}
		
		pPhantom = new hkpCachingShapePhantom(shape, t);
		if(ISNULL(pPhantom)) {
			hr = E_OUTOFMEMORY;
			break;
		}

		m_pPhysics->GetScene()->addPhantom(pPhantom);
		if(m_pPhantom) {
			m_pPhysics->GetScene()->removePhantom(m_pPhantom);
		}
		m_pPhantom = pPhantom;
		m_pParent = pParent;

		//delete m_loader;
		//m_loader = NULL;

		return S_OK;
	}while(false);

	if(pPhantom && m_pPhysics->GetScene())
		m_pPhysics->GetScene()->removePhantom(pPhantom );

	if(m_loader) {
		delete m_loader;
		m_loader = NULL;
	}

	return hr;
}
